import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.example.warehouse.*;



public class WarehouseImplementation implements WarehouseWS{

	//private static final String file_path = "C:/Users/Gramoy/Desktop/ServiceComputing/ds_1_2.xml";
	private static final String file_path = "../datasource/ds_6_2.xml";
	public Marshaller marshaller;
	public Unmarshaller unmarshaller;
	public WareHouse wareHouse;
	
	// Constructor
	public WarehouseImplementation()
	{
		
		try {
			// create the context on package
			ClassLoader cl = org.example.warehouse.ObjectFactory.class.getClassLoader();
			String packageName = WareHouse.class.getPackage().getName();
			JAXBContext jc = JAXBContext.newInstance(packageName, cl);			
			//JAXBContext jc = JAXBContext.newInstance("org.example.warehouse");
			// create marshaller and unmarshaller using context
			this.unmarshaller = jc.createUnmarshaller();
			this.marshaller = jc.createMarshaller();
			// marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			// transform data from XML form to Java Objects and 'cast' the result
			//this.wareHouse = (WareHouse)unmarshaller.unmarshal(file);
			unmarshal(file_path);
			//System.out.println(wareHouse);
			
			/*
			WareHouse wh = new WareHouse();
			ItemInfo ii = new ItemInfo();
			ii.setResourceID("Test");
			ii.setAmount(5);
			ItemList il = new ItemList();
			il.getItem().add(ii);
			wh.setItems(il);
			HoldingRequestInfo hr = new HoldingRequestInfo();
			hr.setRequestID("1Test");
			hr.setItem(ii);
			HoldingRequestList  hrl = new HoldingRequestList();
			hrl.getRequest().add(hr);
			wh.setHoldingReques(hrl);
			ObjectFactory obf = new ObjectFactory();
			JAXBElement<WareHouse> output = obf.createWarehouse(wh);
		    try {
				marshaller.marshal(output, new FileOutputStream("ds_6_2.xml"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			*/
			
			
			//marshaller.marshal(wh, file);
			
			
		   } 
		catch (JAXBException e) { e.printStackTrace(); }
	}
	
	@SuppressWarnings("unchecked")
	private void unmarshal(String file_path)
	{
		JAXBElement<WareHouse> wh = null;
		try {
			wh = (JAXBElement<WareHouse>)unmarshaller.unmarshal(new FileInputStream(file_path));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		wareHouse = wh.getValue();
	}
	
	private void marshal(WareHouse wareHouse, String file_path)
	{
		
		ObjectFactory obf = new ObjectFactory();
		JAXBElement<WareHouse> output = obf.createWarehouse(wareHouse);
	    try {
	    	marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
	    	marshaller.marshal(output, new FileOutputStream(file_path));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	@Override
	public void cancelHoldingItems(String holdingID) {
		List<HoldingRequestInfo> items = getHItemsFromWH();
		int size = items.size();
		for(int i = 0; i < size; i++)
			{
				HoldingRequestInfo h_item = items.get(i);
				if(h_item.getRequestID().equals(holdingID))
				{
					// first remove the holding items from the warehouse
					wareHouse.getHoldingReques().getRequest().remove(i);
					// then return the holding items to the original state
					complementStock(h_item.getItem().getResourceID(), h_item.getItem().getAmount());
					// make sure to make the same changes in XML
					marshal(wareHouse,file_path);
					// if everything works, then return true!
				}

			}
		
	}

	@Override
	
	public int complementStock(String resourceID, int amount) 
	{
		List<ItemInfo> items = getItemsFromWH();
		int size = items.size();
		for(int i = 0; i < size; i++)
			{
				ItemInfo item = items.get(i);
				int wh_amount = item.getAmount();
				if(item.getResourceID().equals(resourceID))
				{
					// add the specific amount to warehouse
					wh_amount += amount;
					wareHouse.getItems().getItem().get(i).setAmount(wh_amount);
					// make sure to make the same changes in XML
					marshal(wareHouse,file_path);
					// if everything works, then return the new amount of items
					return wh_amount;
				} 
					
			}
		// there is nothing to complement? then create a new item!
		ItemInfo itemInfo = new ItemInfo();
		itemInfo.setResourceID(resourceID);
		itemInfo.setAmount(amount);
		wareHouse.getItems().getItem().add(itemInfo);
		// make sure to make the same changes in XML
		marshal(wareHouse,file_path);
		return amount;	
	}

	@Override
	public String holdItems(String resourceID, int amount)
			throws NotEnoughItemException 
	{	
		List<ItemInfo> items = getItemsFromWH();
		int size = items.size();
		for(int i = 0; i < size; i++)
			{
				ItemInfo item = items.get(i);
				int wh_amount = item.getAmount();
				if(item.getResourceID().equals(resourceID) && (amount <= wh_amount))
				{
					// reduce the specific amount of items as they should'nt be available
					wareHouse.getItems().getItem().get(i).setAmount(wh_amount - amount);
					// Generate a request id: Pattern: "HI+resourceID"
					// where + represent concatenation between strings
					String requestID = "HI" + item.getResourceID();
					// create the objects related to holding operation
					// and plug in the needed information
					ItemInfo iteminfo = new ItemInfo();
					iteminfo.setResourceID(resourceID);
					iteminfo.setAmount(amount);
					
					HoldingRequestInfo hr_info = new HoldingRequestInfo();
					hr_info.setRequestID(requestID);
					hr_info.setItem(iteminfo);
					wareHouse.getHoldingReques().getRequest().add(hr_info);
					
					// make sure to make the same changes in XML
					marshal(wareHouse,file_path);
					// if everything works, then return the generated ID!
					return requestID;
				}
			}

		throw new NotEnoughItemException();
	}

	@Override
	public boolean pickupHoldingItems(String holdingID)
			throws InvalidHoldingIDException 
	{ 
		List<HoldingRequestInfo> items = getHItemsFromWH();
		int size = items.size();
		for(int i = 0; i < size; i++)
			{
				HoldingRequestInfo item = items.get(i);
				if(item.getRequestID().equals(holdingID))
				{
					// remove the holding items from warehouse
					wareHouse.getHoldingReques().getRequest().remove(i);
					// make sure to make the same changes in XML
					marshal(wareHouse,file_path);
					// if everything works, then return true!
					return true;
				}
			}
		throw new InvalidHoldingIDException();
	}

	@Override
	public boolean pickupItems(String resourceID, int amount)
			throws NotEnoughItemException 
	{
		List<ItemInfo> items = getItemsFromWH();
		int size = items.size();
		for(int i = 0; i < size; i++)
			{
				ItemInfo item = items.get(i);
				int wh_amount = item.getAmount();
				if(item.getResourceID().equals(resourceID) && (amount <= wh_amount))
				{
					// remove the specific amount from warehouse
					wareHouse.getItems().getItem().get(i).setAmount(wh_amount - amount);
					// make sure to make the same changes in XML
					marshal(wareHouse,file_path);
					// if everything works, then return true!
					return true;
				}
			}
		throw new NotEnoughItemException();
	}

	@Override
	public int query(String resourceID) 
	{
		List<ItemInfo> items = getItemsFromWH();
		int size = items.size();
		for(int i = 0; i < size; i++)
		   {
				ItemInfo item = items.get(i);
				if(item.getResourceID().equals(resourceID))
				{
					return item.getAmount();
				}
		   }
		return 0;
	}
	
	
	private List<ItemInfo> getItemsFromWH()
	{
		return wareHouse.getItems().getItem();
	}
	
	private List<HoldingRequestInfo> getHItemsFromWH()
	{
		return wareHouse.getHoldingReques().getRequest();
	}
	
	

}
